﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Reflection;
using BIStudio.Framework;

using BIStudio.Framework.Data;
using BIStudio.Framework.Utils;
using System.Dynamic;

namespace BIStudio.Framework.Log
{
    [Description("DB")]
    public class DBLogProvider : ILog
    {
        //TODO: DBLogProvider
        private readonly IDBQuery query = CFAspect.Resolve<IDBQuery>();

        public void WriteLog(STDLog info)
        {
            var fieldAndValues = GetFieldAndValues(info);
            var table =
                ALConfig.DllConfigs.IsExists(info.EntityModule) &&
                ALConfig.DllConfigs[info.EntityModule].IsExists("Log") &&
                ALConfig.DllConfigs[info.EntityModule]["Log"].IsExists("Table") ?
                ALConfig.DllConfigs[info.EntityModule]["Log"]["Table"] :
                "STDLog";
            DBBuilder sql = DBBuilder.Insert(table, fieldAndValues);
            query.Execute(sql);
        }

        /// <summary>
        ///     读取日志
        /// </summary>
        /// <param name="condtion"></param>
        /// <returns></returns>
        public List<STDLog> ReadLogs(LogCondtiton condtion)
        {
            var table =
                ALConfig.DllConfigs.IsExists(condtion.EntityModule) &&
                ALConfig.DllConfigs[condtion.EntityModule].IsExists("Log") &&
                ALConfig.DllConfigs[condtion.EntityModule]["Log"].IsExists("Table") ?
                ALConfig.DllConfigs[condtion.EntityModule]["Log"]["Table"] :
                "STDLog";
            var sql = condtion.BuildSqlCondition(DBBuilder.Select(table));
            return AnalysisInfos(query.ToDataTable(sql));
        }

        /// <summary>
        ///     获取属性名和属性值
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        private IDictionary<string, object> GetFieldAndValues(STDLog info)
        {
            IDictionary<string, object> obj = new ExpandoObject();
            info.GetType()
                .GetProperties()
                .Where(item => item.PropertyType.IsValueType || item.PropertyType == typeof(string))
                .Select(item => new KeyValuePair<string, object>(item.Name, item.GetValue(info)))
                .Union(info.Additional.Select(item => new KeyValuePair<string, object>(item.Key, item.Value)))
                .ForEach(item => obj[item.Key] = item.Value);
            return obj;
        }

        /// <summary>
        /// 解析实体
        /// </summary>
        /// <param name="dt"></param>
        /// <returns></returns>
        private List<STDLog> AnalysisInfos(DataTable dt)
        {
            var list = new List<STDLog>();
            foreach (DataRow dr in dt.Rows)
            {
                var info = new STDLog {Additional = new Dictionary<string, object>()};
                PropertyInfo[] properties = typeof (STDLog).GetProperties();

                foreach (DataColumn dc in dr.Table.Columns)
                {
                    PropertyInfo property = properties.FirstOrDefault(d => d.Name == dc.ColumnName);
                    if (property == null)
                    {
                        info.Additional.Add(dc.ColumnName, dr[dc.ColumnName]);
                        continue;
                    }
                    if (property.PropertyType.FullName != "System.String" && !property.PropertyType.IsValueType)
                        continue;
                    property.SetValue(info, dr[dc.ColumnName] == DBNull.Value ? null : dr[dc.ColumnName], null);
                }
                list.Add(info);
            }
            return list;
        }
    }
}